package gen

import (
	"fmt"
	"game/game-design/util"
	"reflect"
	"strings"
)

// #for obj in {{someIter}}
type ForBlock struct {
	CodeBlock
	forNum     int
	isInline   bool
	first      bool
	loopAdd    string
	paramName  string
	expression string
	buffer     *util.StringBuffer
}

func OfForBlock(head string) ICodeBlock {
	var forBlock ForBlock
	forBlock.Head = head
	forBlock.first = true
	forBlock.buffer = util.NewStringBuffer()
	forBlock.forNum = 1

	parts := strings.Split(head, " ")

	forBlock.paramName = parts[1]
	//表达式
	forBlock.expression = parts[3]

	for _, part := range parts {
		if strings.HasPrefix(part, "loopadd") {
			part = strings.Replace(part, "loopadd(", "", 1)
			part = strings.Replace(part, ")", "", 1)
			forBlock.loopAdd = part
		} else if strings.HasPrefix(part, "inline") {
			forBlock.isInline = true
		}
	}
	return &forBlock
}

func (f *ForBlock) Build() {
	defer func() {
		if err := recover(); err != nil {
			fmt.Println("解析", f.expression, "异常")
		}
	}()
	rValue := GetFromExpression(f.expression).(reflect.Value)
	rLen := rValue.Len()
	for i := 0; i < rLen; i++ {
		iValue := rValue.Index(i)
		if iValue.Kind() == reflect.Ptr {
			Params[f.paramName] = iValue.Interface()
		} else {
			Params[f.paramName] = iValue
		}

		build0(f)

		if f.loopAdd != "" && i < rLen-1 {
			if f.isInline {
				f.buffer.Append(f.loopAdd)
			} else {
				f.buildedLines = append(f.buildedLines, f.loopAdd)
			}
		}

		f.first = false
	}

	if f.isInline {
		f.buildedLines = append(f.buildedLines, f.buffer.ToString())
	}
}

func (f *ForBlock) isEnd() bool {
	return f.forNum <= 0
}

func (f *ForBlock) checkStep(line string) {
	if !strings.HasPrefix(line, "#for") {
		return
	}
	if line == "#for end" {
		f.forNum -= 1
	} else {
		f.forNum += 1
	}
}

// 添加行表达式
func (f *ForBlock) addLineExpression(lineExpression string) {
	if f.isInline {
		if f.first {
			f.buffer.Append(ParseFromExpression(lineExpression))
		} else {
			f.buffer.Append(" ").Append(ParseFromExpression(strings.TrimSpace(lineExpression)))
		}
	} else {
		f.buildedLines = append(f.buildedLines, ParseFromExpression(lineExpression))
	}
}

func (f *ForBlock) GetDesc() string {
	return "ForBlock at " + f.Head
}
